﻿
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Linq;

using alib.Collections;
using alib.Concurrency;
using alib.Debugging;
using alib.Enumerable;
using alib.Memory;

namespace agree
{
	using transfer.old;

	public unsafe sealed partial class Unification : IDisposable
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public void _fixup_multi_root_corefs(Tfs atfs_in, IReadOnlyList<RootNodeData> rgrnd, MultiRootTfs shell_for_result)
		{
#if false
			Slot* ps;
			pinfo* pi = _init_tfs(atfs_in);
			int i, c_roots = rgrnd.Count;

			/// init non-root nodes since we want the rmg which the unifier currently doesn't initialize
			ps = ps_base + (pi->uix0 + 1);	/// leaving TOPMST unused for now
			for (i = 0; i < atfs_in.EdgeCount; i++, ps++)
			{
				if (!(atfs_in is WriteableTfs) || atfs_in.entries[i].hash_code != -1)
				{
					arr_tfs_entry ate;
					atfs_in.GetIndexData(i + 1, &ate);
					_init_node(ps, pi->tfsix, ate.rnd);
				}
			}

			/// multi-root slots are at the *end* of the unifier slots, but will be written at the beginning of the TFS
			Slot** pps_rels = stackalloc Slot*[c_roots];
			for (i = 0; i < c_roots; i++, ps++)
				_init_node(pps_rels[i] = ps, pi->tfsix, rgrnd[i]);

			if (!_xdlb_corefs(pi, atfs_in as TfsBuilder.Xdl))
				throw new Exception("Xdl coreferences could not be unified.");

			_prep_multi_root(c_roots, pps_rels);

			_write_to_shell(shell_for_result, c_roots, pps_rels);

			freeU();
#endif
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// deploy inter-grammar corefs
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		bool _xdlb_corefs(pinfo* pi, TfsBuilder.Xdl xdlb)
		{
			if (xdlb != null)
				foreach (var crf in xdlb.corefs.Values)
				{
					var e = crf.GetEnumerator();
					e.MoveNext();
					Slot* ps = _get_slot_index(pi, e.Current.fm);
					while (e.MoveNext())
					{
						if (!_duplex_node(ps, _get_slot_index(pi, e.Current.fm)))
							return false;
						while (ps->forward < 0)
							ps = (Slot*)((long)ps_base - ps->forward);
					}
				}
			return true;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		void _prep_multi_root(int c_roots, Slot** pps_rels)
		{
			ugen = (uint)(gen + 6);
			cgen = (uint)(gen + 7);
			next_mark = 1;
			next_coref_mark = -1;
			count_p3 = 0;

			for (int i = 0; i < c_roots; i++, pps_rels++)
			{
#if false
				Slot* ps = *pps_rels;
				throw new Exception();
				this.tm = _get_slot_tm(ps);
				this.rgpfix = tm.restrictors.r_none.R;

				_count_prep(
					*(ushort**)((long)rgpfix + ((int)ps->f << 3)),
					pbx + ps->tfsix,
					(int)((long)ps - (long)ps_base),
					ps->m_src);

				ps->m_src = next_mark++;
#endif
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		void _write_to_shell(MultiRootTfs xtfs, int c_roots, Slot** pps_rels)
		{
			xtfs.c_roots = c_roots;
			xtfs.c_act = count_p3 + c_roots;
			xtfs.c_corefs = -next_coref_mark - 1;
			xtfs.entries = new arr_tfs_entry[xtfs.c_act > 256 ? xtfs.c_act : 256];

			fixed (ushort* phf = xtfs.h.pfirst)
			fixed (arr_tfs_entry* _pate = xtfs.entries)
			{
				arr_tfs_entry* pate = _pate;
				int i = 0;
				for (; i < c_roots; i++, pps_rels++)
				{
					Slot* ps = *pps_rels;
					pate->e = ps->e;
					pate->i_feat = 0;
					pate->mark = 0;
					//pate->tgrm = ps->tgrm;
					pate++;
				}

				i = _write_multi_root_entries(i, pate, phf);
				Debug.Assert(i == xtfs.c_act);
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		int _write_multi_root_entries(int i, arr_tfs_entry* pate, ushort* phf)
		{
			int t;
			ushort* pus;
			for (Slot* ps = ps_base; ps < ps_last; ps++)
			{
				if (ps->gen == cgen)
				{
					pate->e_ul = ((t = ps->d_over) == 0 ? ps : ((Slot*)((long)ps_base - (t << SHL_PS))))->e_ul;
					*(ushort*)pate = ps->i_feat;

					//pate->tgrm = ps->tgrm;
					pate->mark = (short)*(pus = (ushort*)((long)ps_base + (ps->ix_upper + 20)));
					pate->next = *(pus = phf + (byte)(*(ushort*)pate ^ *pus));

					*pus = (ushort)++i;
					pate++;
				}
			}
			return i;
		}
	};
}